#if defined (_MSC_VER) && (_MSC_VER >= 1020)
#pragma once
#endif

#ifndef JETBYTE_TOOLS_WIN32_THREAD_POOL_INCLUDED__
#define JETBYTE_TOOLS_WIN32_THREAD_POOL_INCLUDED__


#include "IOCompletionPort.h"
#include "Thread.h"
#include "ManualResetEvent.h"
#include "AutoResetEvent.h"
#include "CriticalSection.h"

#include <deque>

///////////////////////////////////////////////////////////////////////////////
// Namespace: OldDreamTools::Win32
///////////////////////////////////////////////////////////////////////////////

namespace OldDreamTools {
namespace Win32 {

///////////////////////////////////////////////////////////////////////////////
// CThreadPool
///////////////////////////////////////////////////////////////////////////////

class CThreadPool : private CThread
{
   public :

      class WorkerThread;

      friend class WorkerThread;

      CThreadPool(
         size_t initialThreads,
         size_t minThreads,
         size_t maxThreads,
         size_t maxDormantThreads,
         size_t poolMaintPeriod,
         size_t dispatchTimeout,
         size_t maxThreadsDispatchTimeout);

      virtual ~CThreadPool();

      using CThread::Start;

      void InitiateShutdown();

      void WaitForShutdownToComplete(
         size_t timeout = INFINITE,
         bool forceTermination = false);

   protected :

      void Dispatch(
         ULONG_PTR completionKey,
         DWORD dwNumBytes = 0,
         OVERLAPPED *pOverlapped = 0);

   private :

      void ThreadStarted();

      virtual void OnThreadStarted() {};

      void ThreadInitialised();

      virtual void OnThreadInitialised() {};

      void ProcessingStarted();

      virtual void OnProcessingStarted() {};

      void ReceivedMessage();

      virtual void OnReceivedMessage() {};

      void ProcessingStopped();

      virtual void OnProcessingStopped() {};

      void ThreadStopped(
         WorkerThread *pThread);

      virtual void OnThreadStopped() {};

      int Run();

      void StartWorkerThread();

      virtual WorkerThread *CreateWorkerThread(
         CIOCompletionPort &iocp,
         CEvent &messageReceivedEvent,
         CThreadPool &pool) = 0;

      void HandleDormantThreads();

      void StopWorkerThreads(
         size_t numThreads);

      void TerminateWorkerThreads();

      void AddThreadToList(
         WorkerThread *pThread);

      void RemoveThreadFromList(
         WorkerThread *pThread);

      void HandleDispatch(
         ULONG_PTR completionKey,
         DWORD dwNumBytes,
         OVERLAPPED *pOverlapped);

      CManualResetEvent m_shutdownEvent;
      CManualResetEvent m_dispatchCompleteEvent;
      CManualResetEvent m_poolEmptyEvent;

      CCriticalSection m_criticalSection;

      CIOCompletionPort m_workPort;
      CIOCompletionPort m_dispatchPort;

      long m_activeThreads;
      long m_initialisedThreads;
      long m_processingThreads;

      const size_t m_initialThreads;
      const size_t m_minThreads;
      const size_t m_maxThreads;
      const size_t m_maxDormantThreads;

      WorkerThread *m_pHead;

      const size_t m_poolMaintPeriod;
      const size_t m_dispatchTimeout;
      const size_t m_maxThreadsDispatchTimeout;
};

///////////////////////////////////////////////////////////////////////////////
// CThreadPool::WorkerThread
///////////////////////////////////////////////////////////////////////////////

class CThreadPool::WorkerThread : public CThread
{
   friend class CThreadPool;

   protected :

      WorkerThread(
         CIOCompletionPort &iocp,
         CEvent &messageReceivedEvent,
         CThreadPool &pool);

      virtual ~WorkerThread();

   private :

      virtual bool Initialise();

      virtual void Process(
         ULONG_PTR completionKey,
         DWORD dwNumBytes,
         OVERLAPPED *pOverlapped) = 0;

      virtual void Shutdown();

      virtual int Run();

      CEvent &m_messageReceivedEvent;

      CIOCompletionPort &m_iocp;

      CThreadPool &m_pool;

      WorkerThread *m_pNext;
      WorkerThread *m_pPrev;
};

///////////////////////////////////////////////////////////////////////////////
// Namespace: OldDreamTools::Win32
///////////////////////////////////////////////////////////////////////////////

} // End of namespace Win32
} // End of namespace OldDreamTools

///////////////////////////////////////////////////////////////////////////////
// Lint options
//
//lint -restore
//
///////////////////////////////////////////////////////////////////////////////

#endif // JETBYTE_TOOLS_WIN32_THREAD_POOL_INCLUDED__

///////////////////////////////////////////////////////////////////////////////
// End of file
///////////////////////////////////////////////////////////////////////////////
